{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"../common/rfsoc_book_banner.jpg\" alt=\"University of Strathclyde\" align=\"left\">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-block\" style=\"background-color: #c7b8d6; padding: 10px\">\n",
    "    <p style=\"color: #222222\">\n",
    "        <b>Note:</b>\n",
    "        <br>\n",
    "        This Jupyter notebook uses hardware features of the Zynq UltraScale+ RFSoC device. Therefore, the notebook cells will only execute successfully on an RFSoC platform.\n",
    "    </p>\n",
    "</div>\n",
    "\n",
    "# Notebook Set G\n",
    "\n",
    "---\n",
    "\n",
    "## 02 - RFSoC Radio Observe\n",
    "This notebook introduces the transmitter and receiver of the RFSoC radio system. We will first explore the transmitter pipeline, which includes the symbol generator, Root-Raise-Cosine (RRC) transmit filter and Cascaded Integrator-Comb (CIC) interpolator. We will also investigate the receiver stages, which include the CIC decimator, coarse frequency synchroniser, RRC receive filter, time synchroniser, and phase synchroniser. We will plot the output waveform of each stage using a visualisation tool, which allows us to inspect the constellation, time domain, and frequency domain plots.\n",
    "\n",
    "## Table of Contents\n",
    "* [1. Introduction](#introduction)\n",
    "* [2. Transmitter](#transmitter)\n",
    "    * [2.1. Symbol Generator](#data-generator)\n",
    "    * [2.2. RRC Transmit Filter](#rrc-tx)\n",
    "    * [2.3. CIC Interpolator](#cic_interpolator)\n",
    "* [3. Receiver](#receiver)\n",
    "    * [3.1. CIC Decimator](#cic_decimator)\n",
    "    * [3.2. Coarse Frequency Synchronisation](#coarse-freq-sync)\n",
    "    * [3.3. RRC Receive Filter](#rrc-rx)\n",
    "    * [3.4. Time Synchronisation](#time-sync)\n",
    "    * [3.5. Phase Synchronisation](#phase-sync)\n",
    "* [4. Conclusion](#conclusion)\n",
    "\n",
    "## References\n",
    "* [1] - [Xilinx, Inc, \"USP RF Data Converter: LogiCORE IP Product Guide\", PG269, v2.4, November 2020](https://www.xilinx.com/support/documentation/ip_documentation/usp_rf_data_converter/v2_4/pg269-rf-data-converter.pdf)\n",
    "* [2] - [Stewart, R. W., Barlee, K. W., Atkinson, D. S. W., & Crockett, L. H. (2015). Software Defined Radio using MATLAB & Simulink and the RTL-SDR. (1 ed.)](https://www.desktopsdr.com/)\n",
    "\n",
    "## Revision\n",
    "* **v1.0** | 16/01/23 | *First Revision*\n",
    "\n",
    "---\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. Introduction\n",
    "Let us begin by programming the FPGA bitstream and initialising the PYNQ overlay design. To do this, we need to import the `rfsoc_radio` package. We also need to initialise the overlay.\n",
    "\n",
    "Upon executing the code cell below, two tests will run to ensure the radio system is operational. If these tests fail, check your platform's loopback connection, restart the kernel, and try running the code cell again.\n",
    "\n",
    "<div class=\"alert alert-box alert-danger\">\n",
    "<b>Caution:</b>\n",
    "    In this demonstration, we generate signals using the RFSoC development board. Your device should be setup in loopback mode. You should understand that the RFSoC platform can also transmit RF signals wirelessly. Remember that unlicensed wireless transmission of RF signals may be illegal in your geographical location. Radio signals may also interfere with nearby devices, such as pacemakers and emergency radio equipment. Note that it is also illegal to intercept and decode particular RF signals. If you are unsure, please seek professional support.\n",
    "</div>\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from rfsoc_radio.overlay import RadioOverlay\n",
    "\n",
    "ol = RadioOverlay(run_test=True)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This demonstration has two primary software objects in the overlay design. The first is `ol.radio_transmitter`, which is the software wrapper responsible for controlling the BPSK and QPSK transmitter and corresponding Direct Memory Access (DMA) IP cores. Similarly, the second is `ol.radio_receiver`, which is another software wrapper that controls the BPSK and QPSK receiver and associated DMA. Each software wrapper can be queried by using the help function to display their doc string. Try this in the cell below for each of the software wrappers:\n",
    "\n",
    "```python\n",
    "help(ol.radio_receiver)\n",
    "help(ol.radio_transmitter)\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "help(ol.radio_receiver)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In the previous notebook, we launched a dashboard to control the radio system. We can launch this again by running the following code cell."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ol.dashboard()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* _**After you have executed the above cell, you should right click the radio dashboard, and select \"Create New View for Output\" from the drop-down menu. This will allow you to interact with the notebook and retain access to the radio dashboard in another output view.**_"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. The Transmitter <a class=\"anchor\" id=\"the-transmitter\"></a>\n",
    "The transmitter modulates 8 bit fixed point data into BPSK or QPSK packets for transmission. Initially, the 8 bit wide data is serialised and modulated. The transmission system uses a Root-Raise-Cosine (RRC) filter to pulse shape the modulated data, and then interpolates the samples to 1.024 GSa/s. The pulse shaped, interpolated data is modulated with a carrier frequency and transmitted using the RF DAC. An overview of the transmitter can be seen in Figure 1.\n",
    "\n",
    "<figure> <a class=\"anchor\" id=\"fig-3\"></a>\n",
    "    <img src=\"images/transmitter.png\" style=\"width: 90%;\"/>\n",
    "    <figcaption><b>Figure 3: System architecture of the transmitter.</b></figcaption>\n",
    "</figure>\n",
    "\n",
    "When the transmitter hardware system was designed, a data inspector was added that will allow you to transfer frames of data from the PL to the external memory. Software has been developed that manipulates the samples of data for visualisation using the Python Plotly library. You can try this for yourself by running the code cell below."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ol.radio_transmitter.visualise()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Upon executing the cell above you will be presented with constellation, time domain and frequency spectrum plots. These plots can be continuously updated by clicking the play button. You are able to visualise other points in the transmitter by using the observation point dropdown menu.\n",
    "\n",
    "* _**Right-click the area above, and in the drop-down menu that appears, select \"Create New View for Output\". This action will move the plots to another window in Jupyter Labs, allowing you to scroll further down the notebook while still being able to visualise and interact with the plots.**_\n",
    "\n",
    "### 2.1. Symbol Generator <a class=\"anchor\" id=\"symbol-generator\"></a>\n",
    "We will now take a moment to inspect each stage of the transmitter using the visualisation tools. The first stage is the symbol generator, which is responsible for interfacing to the DMA controller and generating pseudo-random data. The input data is digitally modulated using differential BPSK, or differential QPSK. We can inspect these symbols using constellation and time plots.\n",
    "\n",
    "* *Using the transmitter visualisation tool, select the constellation tab.*\n",
    "* *Now, ensure that the observation point dropdown menu is set to symbol generation.*\n",
    "\n",
    "You should be able to see symbols plotted on a constellation plot after following the instructions above. An example plot is presented in Figure 2. You can try to change the modulation scheme by using the modulation dropdown menu in the radio dashboard.\n",
    "\n",
    "<figure> <a class=\"anchor\" id=\"fig-2\"></a>\n",
    "    <img src=\"images/tx_symbol_constellation.png\" style=\"width: 75%;\"/>\n",
    "    <figcaption><b>Figure 2: Constellation plot of QPSK symbols generated in the transmitter pipeline.</b></figcaption>\n",
    "</figure>\n",
    "\n",
    "You can also inspect the time domain output of the symbol generator.\n",
    "\n",
    "* *Select the time tab of the transmitter visualisation tool.*\n",
    "\n",
    "A time domain plot will be shown similar to the example given in Figure 3.\n",
    "\n",
    "<figure> <a class=\"anchor\" id=\"fig-3\"></a>\n",
    "    <img src=\"images/tx_symbol_time.png\" style=\"width: 75%;\"/>\n",
    "    <figcaption><b>Figure 3: Time plot of QPSK symbols generated in the transmitter pipeline.</b></figcaption>\n",
    "</figure>\n",
    "\n",
    "Here, we can see symbols that will later be pulse shaped, interpolated, and modulated for transmission. You can also change the modulation scheme employed by the transmitter. Selecting BPSK will remove the quadrature (Q) component and keep the in-phase (I) component. A QPSK data stream will have both I and Q channels active.\n",
    "\n",
    "### 2.2. RRC Transmit Filter <a class=\"anchor\" id=\"rrc-tx\"></a>\n",
    "An RRC filter is required to suppress intersymbol interference (ISI). One filter is required at the transmitter, and the another is placed at the receiver. We can inspect the time domain plot of the pulse shaped symbols.\n",
    "\n",
    "* *Select the time tab of the transmitter visualisation tool.*\n",
    "* *Now, select the raised cosine filter from the observation point dropdown menu.*\n",
    "\n",
    "Swapping between BPSK and QPSK using the radio dashboard switches the Q component on and off. An example time domain plot of the RRC output is presented in Figure 4.\n",
    "\n",
    "<figure> <a class=\"anchor\" id=\"fig-4\"></a>\n",
    "    <img src=\"images/tx_rrc_time.png\" style=\"width: 75%;\"/>\n",
    "    <figcaption><b>Figure 4: Time plot of pulse shaped QPSK symbols from the transmitter pipeline.</b></figcaption>\n",
    "</figure>\n",
    "\n",
    "We can also inspect the frequency spectra of the pulse shaped symbols.\n",
    "\n",
    "* *Click on the spectrum tab of the transmitter visualisation tool.*\n",
    "\n",
    "Our radio system operates at 100kSa/s, which means we should be able to see a band that is 100kHz wide in the spectrum plot. When we select BPSK modulation, you will be able to see a double-sided spectrum that is symmetrical over 0Hz. If QPSK modulation is selected, the double-sided spectrum plot is no longer symmetrical over 0Hz as a complex waveform is used instead. An example spectrum plot is given in Figure 5.\n",
    "\n",
    "<figure> <a class=\"anchor\" id=\"fig-5\"></a>\n",
    "    <img src=\"images/tx_rrc_spectrum.png\" style=\"width: 75%;\"/>\n",
    "    <figcaption><b>Figure 5: Spectra of pulse shaped QPSK symbols from the transmitter pipeline.</b></figcaption>\n",
    "</figure>\n",
    "\n",
    "### 2.3. CIC Interpolator <a class=\"anchor\" id=\"cic-interpolator\"></a>\n",
    "The final stage of the transmitter pipeline that we can visualise is the Cascaded Integrator-Comb (CIC) interpolator. Interpolation increases the sample frequency of our waveform to meet the sampling requirements of the RF DAC. The CIC interpolator increases the sample frequency by a factor of 320.\n",
    "\n",
    "* *Click the time tab of the transmitter visualisation tool.*\n",
    "* *Now, select the CIC interpolator from the observation point dropdown menu.*\n",
    "\n",
    "The time domain plot should reveal a waveform that has very smooth transitions between 1 and -1 i.e. a waveform that does not have sharp changes in amplitude. An example is given in Figure 6.\n",
    "\n",
    "<figure> <a class=\"anchor\" id=\"fig-6\"></a>\n",
    "    <img src=\"images/tx_interp_time.png\" style=\"width: 75%;\"/>\n",
    "    <figcaption><b>Figure 6: Time domain plot of a complex interpolated waveform.</b></figcaption>\n",
    "</figure>\n",
    "\n",
    "We can also inspect the frequency spectra of the waveform.\n",
    "\n",
    "* *Click the spectrum tab of the transmitter visualisation tool.*\n",
    "\n",
    "We can clearly see that the spectra of the waveform is over 0Hz. Your transmitter plot should be similar to the example given in Figure 7.\n",
    "\n",
    "<figure> <a class=\"anchor\" id=\"fig-7\"></a>\n",
    "    <img src=\"images/tx_interp_spectrum.png\" style=\"width: 75%;\"/>\n",
    "    <figcaption><b>Figure 7: Spectra of a complex interpolated waveform.</b></figcaption>\n",
    "</figure>\n",
    "\n",
    "When the interpolated waveform is transferred to the RF DAC, a fine mixer will modulate the waveform to a higher frequency for transmission.\n",
    "\n",
    "* **_You can now press the stop button on the transmitter visualiser and close the output view._**\n",
    "\n",
    "In the next section, we will investigate the receiver pipeline."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. The Receiver <a class=\"anchor\" id=\"the-receiver\"></a>\n",
    "The receiver consists of five stages that help it acquire a BPSK or QPSK waveform. These stages are:\n",
    "* Decimation\n",
    "* Coarse Frequency Synchronisation\n",
    "* Matched Filtering\n",
    "* Time and Phase Synchronisation\n",
    "* Frame Synchronisation\n",
    "\n",
    "You can see each of these stages below in Figure 8. Notice that the final stage, frame synchronisation, is directly connected to a DMA controller. This allows the RFSoC's PL to transfer demodulated frames into Jupyter Labs, via external memory.\n",
    "\n",
    "<figure> <a class=\"anchor\" id=\"fig-8\"></a>\n",
    "    <img src=\"images/receiver.png\" style=\"width: 90%;\"/>\n",
    "    <figcaption><b>Figure 8: System architecture of the receiver.</b></figcaption>\n",
    "</figure>\n",
    "\n",
    "The decimation stage significantly decreases the sample rate of the signal to 12.8MSa/s. Coarse frequency synchronisation is then performed correcting frequency offsets up to 1.6MHz. These frequency offsets must be larger than 195.3125Hz in order for the coarse frequency synchroniser to correct the signal. A matched root rasied cosine filter is then applied to the signal to suppress intersymbol interference. Time and phase synchronisation obtains the maximum effect points of the signal and decides whether the received signal is a binary 1 or 0. Finally, frame synchronisation is performed by correlating an extended barker sequence with the received binary data. This detects the start of the frame, which is transferred into system memory by the DMA.\n",
    "\n",
    "When the receiver hardware system was designed, a data inspector was added that will allow you to transfer frames of data from the PL to the external memory. Software has been developed that manipulates the samples of data for visualisation using the Python Plotly library. You can try this for yourself by running the code cell below."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ol.radio_receiver.visualise()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Upon executing the cell you will be presented with time domain, constellation, and frequency spectrum plots. These plots can be continuously updated by clicking the start button. You are able to visualise other points in the receiver by using the observation point dropdown menu.\n",
    "\n",
    "* _**Right-click the area above, and in the drop-down menu that appears, select \"Create New View for Output\". This action will move the plots to another window in Jupyter Labs, allowing you to scroll further down the notebook while still being able to visualise and interact with the plots.**_"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.1. CIC Decimator <a class=\"anchor\" id=\"cic-decimator\"></a>\n",
    "The RF ADC begins by demodulating the received signal. The sample frequency of the signal is then reduced by a CIC decimator. We can inspect the output spectra of CIC decimator using the receiver visualisation tool.\n",
    "\n",
    "* *Click the spectrum tab of the receiver visualisation tool.*\n",
    "* *Now, select CIC decimator from the observation point dropdown menu.*\n",
    "\n",
    "You should be able to see a main lobe that is not centred on 0Hz. There should be a frequency offset of approximately 1MHz. If you look at the radio dashboard, the RF DAC centre frequency is 100MHz, while the RF ADC centre frequency is 101MHz. An example of plot of the received spectra is given in Figure 9.\n",
    "\n",
    "<figure> <a class=\"anchor\" id=\"fig-9\"></a>\n",
    "    <img src=\"images/rx_decim_spectrum.png\" style=\"width: 75%;\"/>\n",
    "    <figcaption><b>Figure 9: Spectra of the received waveform after the CIC decimator.</b></figcaption>\n",
    "</figure>\n",
    "\n",
    "### 3.2. Coarse Frequency Synchronisation <a class=\"anchor\" id=\"coarse-freq-sync\"></a>\n",
    "Coarse frequency offsets commonly occur when the centre frequency of the received signal is not known, or when there is a small frequency offset between the transmitter and receiver. We can correct coarse frequency offsets by using a coarse frequency synchronisation stage. We can inspect the output spectra after coarse frequency synchronisation.\n",
    "\n",
    "* *Click the spectrum tab of the receiver visualisation tool.*\n",
    "* *Select the coarse synchronisaton option from the observation point dropdown menu.*\n",
    "\n",
    "You will notice that the 1MHz offset has now been corrected in the output spectra. An example of the spectra is plotted in Figure 10 below.\n",
    "\n",
    "<figure> <a class=\"anchor\" id=\"fig-10\"></a>\n",
    "    <img src=\"images/rx_coarse_spectrum.png\" style=\"width: 75%;\"/>\n",
    "    <figcaption><b>Figure 10: Spectra of the coarse synchronised waveform.</b></figcaption>\n",
    "</figure>\n",
    "        \n",
    "The coarse frequency synchronisation stage is essential as it centres the received signal over 0Hz. This procedure is necessary to extract the data payload. The radio dashboard also reports the frequency offset that is corrected in the coarse frequency synchronisation stage. Be aware that the coarse frequency synchroniser can only correct 1.6MHz offsets. If the signal's offset frequency is larger than 1.6MHz, the reported frequency offset will be incorrect.\n",
    "\n",
    "### 3.3. RRC Receive Filter <a class=\"anchor\" id=\"rrc-rx\"></a>\n",
    "The matched filter stage is necessary to suppress ISI. We can inspect the spectrum of the output waveform using the receiver visualisation tool.\n",
    "\n",
    "* *Click the spectrum tab of the receiver visualisation tool.*\n",
    "* *Select the raised cosine filter option from the observation point dropdown menu.*\n",
    "\n",
    "You should be able to use the cursor tools on the plot to obtain and measure the bandwidth of the received signal, which should be approximately 100kHz. An example spectrum plot is given in Figure 11.\n",
    "\n",
    "<figure> <a class=\"anchor\" id=\"fig-11\"></a>\n",
    "    <img src=\"images/rx_rrc_spectrum.png\" style=\"width: 75%;\"/>\n",
    "    <figcaption><b>Figure 11: Spectra of the output waveform after matched filtering.</b></figcaption>\n",
    "</figure>\n",
    "\n",
    "### 3.4. Time Synchronisation <a class=\"anchor\" id=\"time-sync\"></a>\n",
    "We are now very close to acquiring the received signal with time and phase synchronisation remaining. Time synchronisation is performed by evaluating the point in a signal that contains the transmitted data. Using the inspection tool, we can visualise the effects of correct time synchronisation.\n",
    "\n",
    "* *Set the observation point to time synchronisation.*\n",
    "* *Now, inspect the time domain and constellation plots using the tabs.*\n",
    "\n",
    "You will be able to clearly see that the time domain plot is shaped like a saw tooth. This has occured because the time synchronisation algorithm is selecting the most effective points to sample and retrieve data. An example of the time domain plot is given in Figure 12.\n",
    "\n",
    "<figure> <a class=\"anchor\" id=\"fig-12\"></a>\n",
    "    <img src=\"images/rx_timesync_time.png\" style=\"width: 75%;\"/>\n",
    "    <figcaption><b>Figure 12: Time domain plot of the received QPSK waveform after time synchronisation.</b></figcaption>\n",
    "</figure>\n",
    "\n",
    "In the constellation plot, a QPSK or BPSK signal can be seen, which is rotating in a circular motion. This rotation occurs because the real and imaginary components of the signal are changing in amplitude over time. The amplitude is changing because the signal is not carrier synchronised (or phase aligned correctly). See the constellation plot given in Figure 13 for an example of the time synchronised waveform.\n",
    "\n",
    "<figure> <a class=\"anchor\" id=\"fig-13\"></a>\n",
    "    <img src=\"images/rx_timesync_constellation.png\" style=\"width: 75%;\"/>\n",
    "    <figcaption><b>Figure 13: Constellation plot of the received QPSK waveform after time synchronisation.</b></figcaption>\n",
    "</figure>\n",
    "\n",
    "### 3.5. Phase Synchronisation <a class=\"anchor\" id=\"phase-sync\"></a>\n",
    "The final stage before we can extract a data payload from the signal is phase synchronisation. This stage allows us to rotate the received constellation to appropriately adjust the amplitude of the in-phase and quadrature components. The inspection tool can be used to visualise the effect of phase synchronisation.\n",
    "\n",
    "* *Change the observation point to phase synchronisation.*\n",
    "* *Using the time domain and constellation plots to inspect the phase synchronised waveform.*\n",
    "\n",
    "Notice that the constellation has stopped rotating and the time domain signal has stabilised. An example of the constellation plot after phase synchronisation can be inspected in Figure 14. This signal is now ready for frame synchronisation.\n",
    "\n",
    "<figure> <a class=\"anchor\" id=\"fig-14\"></a>\n",
    "    <img src=\"images/rx_phasesync_constellation.png\" style=\"width: 75%;\"/>\n",
    "    <figcaption><b>Figure 14: Constellation plot of the received QPSK waveform after phase synchronisation.</b></figcaption>\n",
    "</figure>\n",
    "\n",
    "* **_You should stop the visualisation tool before progressing to the next notebook._**"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. Conclusion\n",
    "This notebook has introduced the transmitter and receiver of the RFSoC radio system. We first explored the transmitter's symbol generation, RRC transmit filter, and CIC interpolation stages. An inspection and plotting tool was used to observe the outputs of each stage.\n",
    "\n",
    "Similarly, we also investigated the receiver pipeline, which consisted of a CIC decimator, coarse frequency synchroniser, RRC receive filter, time synchroniser, and phase synchroniser. The output of each of these stages were inspected using the receiver visualisation tool.\n",
    "\n",
    "In the next notebook, we will transmit and receive data using the RFSoC radio system."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "[⬅️ Previous Notebook](01_rfsoc_radio_system.ipynb) || [Next Notebook 🚀](03_rfsoc_radio_helloworld.ipynb)\n",
    "\n",
    "Copyright © 2023 Strathclyde Academic Media\n",
    "\n",
    "---\n",
    "---"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
